package com.unitd.logistics.service.impl;

import com.google.common.collect.Maps;
import com.unitd.logistics.comm.enums.ResultEnum;
import com.unitd.logistics.comm.exception.LogisticsException;
import com.unitd.logistics.comm.file.ExcelUtils;
import com.unitd.logistics.comm.utils.FileUtils;
import com.unitd.logistics.comm.utils.ListUtils;
import com.unitd.logistics.model.pojo.TablesColInfoPo;
import com.unitd.logistics.model.pojo.TablesInfoPo;
import com.unitd.logistics.mybatis.mapper.TablesColInfoMapper;
import com.unitd.logistics.mybatis.mapper.TablesInfoMapper;
import com.unitd.logistics.service.ExportTableDataToFileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 处理实际的上传的快递信息文件并调用相应的接口获取接口
 *
 * @author hudan
 * @version 1.0
 * @filename ExportTableDataToFileServiceImpl.java
 * @copyright www.pactera.com
 * @date 2020-05-22
 */
@Service
@Slf4j
public class ExportTableDataToFileServiceImpl implements ExportTableDataToFileService {

	@Autowired
	private TablesInfoMapper tablesInfoMapper;
	@Autowired
	private TablesColInfoMapper tablesColInfoMapper;

	/**
	 * 根据传递的导出文件的路径,将需要导出的数据库表的数据字典信息写入指定文件中
	 *
	 * @param excelFilePath 需要写入结果的数据文件
	 */
	@Override
	public void exportTableDataToExcel(String excelFilePath) {
		try {
			File exportExcelFile = new File(excelFilePath);
			if (!exportExcelFile.exists()) {
				exportExcelFile.createNewFile();
			}


			// 先写入表名信息sheet
			// 定义表头
//        String[] title = {"对应Sheet页", "表名", "中文描述", "表类型", "记录数估算", "数据增长速度"};


			// 读取需要查询的excel文件内容
			Map<String, TablesInfoPo> tablesMapData = getTablesMapData();
			if (null == tablesMapData) {
				return;
			}

			// 遍历读取到的内容,并逐个写入excel文件
			exportDataToExcel(exportExcelFile, tablesMapData);
			log.info("导入-转换数据-导出完成! 结果文件为: {}", exportExcelFile);
		} catch (Exception e) {
			throw new RuntimeException("导出文件失败:[{}]" + e);
		}
	}

	/**
	 * 得到表信息Map集合,其中以表名为key,表对象信息为值
	 *
	 * @return 表信息Map集合
	 */
	private Map<String, TablesInfoPo> getTablesMapData() {

		List<TablesInfoPo> tablesInfos = tablesInfoMapper.selectByCommentNotNull();
		if (!ListUtils.isNull(tablesInfos)) {
			// 将list转换成map,以表名作为key
			return tablesInfos.stream().collect(Collectors.toMap(TablesInfoPo::getTableName, Function.identity(), (key1, key2) -> key2));
		}
		return null;
	}

	/**
	 * @param exportExcelFile 需要导出的文件
	 * @param dataMap         表名信息集合
	 */
	private void exportDataToExcel(File exportExcelFile, Map<String, TablesInfoPo> dataMap) {

		// 创建导出的excel文件并定义excel文件中相应的样式等信息
		Map<String, Object> excelFileInfoMap = createExportExcelFile(exportExcelFile);

		// 遍历读取到的内容,并逐个写入excel文件
		dataMap.forEach((key, value) -> {

			// 单个sheet的名称
			String sheetName = "表定义-" + key;

			// 获取某个表下的具体字段详情
			List<TablesColInfoPo> tableColInfos = tablesColInfoMapper.selectByTableName(key);

			// 将数据写入exce
			writeDataToExcel(sheetName, excelFileInfoMap, exportExcelFile, tableColInfos);
		});
	}

	/**
	 * @param exportExcelFile excel文件名
	 * @return excel文件信息
	 * 创建导出的excel文件并定义excel文件中相应的样式等信息
	 */
	private Map<String, Object> createExportExcelFile(File exportExcelFile) {

		Map<String, Object> excelMap = Maps.newHashMap();

		/* 创建excel文件 */
		try {
			if (!exportExcelFile.exists()) {
				exportExcelFile.createNewFile();
			}
		} catch (IOException e) {
			throw new LogisticsException(ResultEnum.CREATE_EXCEL_FILE_ERROR);
		}

		/* 创建excel工作簿 */
		Workbook workbook;
		if (ExcelUtils.isExcel2007(exportExcelFile.getName())) {
			workbook = new XSSFWorkbook();
		} else {
			workbook = new HSSFWorkbook();
		}

		/* 创建字体样式 */
		Font headerFont = workbook.createFont();
		// 字体加粗
		headerFont.setBold(true);
		// 设置颜色
		headerFont.setColor((short) 8);
		// 设置字体
		headerFont.setFontName("宋体");
		// 设置字体大小
		headerFont.setFontHeightInPoints((short) 18);

		/* 设置导出excel的样式 */
		// 创建标题样式
		CellStyle headerStyle = workbook.createCellStyle();
		// 设置水平居左
		headerStyle.setAlignment(HorizontalAlignment.CENTER);
		// 设置垂直居中
		headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
		// 为标题样式设置字体样式
		headerStyle.setFont(headerFont);

		// 创建标题样式
		CellStyle bodyStyle = workbook.createCellStyle();
		// 设置水平居左
		bodyStyle.setAlignment(HorizontalAlignment.LEFT);
		// 设置垂直居中
		bodyStyle.setVerticalAlignment(VerticalAlignment.CENTER);

		String[] indexTitle = {"对应Sheet页", "表名", "中文描述", "表类型", "记录数估算", "数据增长速度", "备注"};
		String[] title = {"顺序号", "字段名", "字段类型", "是否可空", "是否主键", "关联表", "关联字段", "字段说明"};

		excelMap.put("workbook", workbook);
		excelMap.put("headerFont", headerFont);
		excelMap.put("headerStyle", headerStyle);
		excelMap.put("bodyStyle", bodyStyle);
		excelMap.put("indexTitle", indexTitle);
		excelMap.put("title", title);
		return excelMap;
	}

	/**
	 * 将数据表列字段信息写入excel文件
	 *
	 * @param tablesColInfos  需要写入的数据
	 * @param exportExcelFile 写入后的文件路径
	 * @return 写入数据后的excel文件
	 */
	private File writeDataToExcel(String sheetName, Map<String, Object> excelFileInfoMap, File exportExcelFile, List<TablesColInfoPo> tablesColInfos) {

		// 得到excel工作簿
		Workbook workbook = (Workbook) excelFileInfoMap.get("workbook");
		// 得到标题样式
		CellStyle headerStyle = (CellStyle) excelFileInfoMap.get("headerStyle");
		// 得到内容样式
		CellStyle bodyStyle = (CellStyle) excelFileInfoMap.get("bodyStyle");
		// 定义表头
		String[] title = (String[]) excelFileInfoMap.get("title");

		// 得到工作表sheet
		Sheet sheet = workbook.createSheet(sheetName);

		// 创建第一行
		Row row = sheet.createRow(0);
		// 创建第一行数据的表头
		Cell cell;
		for (int i = 0; i < title.length; i++) {
			// 设置每个单元格的宽度
			if (i == 0) {
				sheet.setColumnWidth(i, 10 * 256);
			} else if (i == title.length - 1) {
				sheet.setColumnWidth(i, 30 * 256);
			} else {
				sheet.setColumnWidth(i, 20 * 256);
			}

			// 创建单元格并赋值
			cell = row.createCell(i);
			cell.setCellValue(title[i]);
			cell.setCellStyle(headerStyle);
		}

		// 写入具体数据
		int rowNum = 1;
		for (TablesColInfoPo tablesColInfo : tablesColInfos) {
			// 创建具体的数据行和 创建具体数据行的单元格并赋值  表头列: {"顺序号", "字段名", "字段类型", "是否可空", "是否主键", "关联表", "关联字段", "字段说明"}
			Row nrow = sheet.createRow(rowNum);

			// 顺序号
			Cell ncell = nrow.createCell(0);
			ncell.setCellValue("" + rowNum);
			// 字段名
			ncell = nrow.createCell(1);
			ncell.setCellValue("" + tablesColInfo.getColumnName());
			// 字段类型
			ncell = nrow.createCell(2);
			ncell.setCellValue("" + tablesColInfo.getDataType());
			// 是否可空
			ncell = nrow.createCell(3);
			ncell.setCellValue("" + tablesColInfo.getNullable());
			// 是否主键
			ncell = nrow.createCell(4);
			ncell.setCellValue("" + tablesColInfo.getIskey());
			// 关联表
			ncell = nrow.createCell(5);
			ncell.setCellValue("	");
			// 关联字段
			ncell = nrow.createCell(6);
			ncell.setCellValue("	");
			// 字段说明
			ncell = nrow.createCell(7);
			ncell.setCellValue("" + tablesColInfo.getCommentdes());
			ncell.setCellStyle(bodyStyle);
			rowNum++;
		}

		// 将数据写入excel
		try {
			FileOutputStream stream = FileUtils.openOutputStream(exportExcelFile);
			workbook.write(stream);
			stream.close();
		} catch (IOException e) {
			throw new LogisticsException(ResultEnum.READ_EXCEL_FILE_ERROR);
		}

		return exportExcelFile;
	}
}